﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Configurator.cs" company="SoftServe">
//   071C#
// </copyright>
// <summary>
//   The server configuration.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace WebServer.BusinessLogic
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Net;
    using System.Xml.Serialization;

    /// <summary>
    /// The server configuration.
    /// </summary>
    public enum ServerConfiguration
    {
        /// <summary>
        /// Load balancer mode.
        /// </summary>
        LoadBalancer, 

        /// <summary>
        /// Redirect mode.
        /// </summary>
        Redirect, 

        /// <summary>
        /// Normal mode.
        /// </summary>
        Normal, 
    }

    /// <summary>
    ///   Initialaze starting
    /// </summary>
    public class Configurator : INotifyPropertyChanged
    {
        #region Static Fields

        /// <summary>
        /// Configurator instance.
        /// </summary>
        private static Configurator instance;

        #endregion

        #region Fields

        /// <summary>
        /// Load balancer addresses.
        /// </summary>
        private ObservableCollection<string> loadBalancerAddresses;

        /// <summary>
        /// The _port.
        /// </summary>
        private int port;

        /// <summary>
        /// The remote servers list.
        /// </summary>
        private List<string> remoteServers;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Prevents a default instance of the <see cref="Configurator"/> class from being created.
        /// </summary>
        private Configurator()
        {
            this.Port = 8080;
            this.ServerMode = ServerConfiguration.Normal;
            this.MaxUsers = 500;
            this.RelativeWwwPath = "www";
            this.ServerName = "MyHttpServer";
            this.Version = "1.0";
            this.IsCookielessSession = false;
            this.EnableLogging = true;
            this.UseResponseCompression = true;

            // administrator configuration
            this.AdminLogin = "Admin";
            this.AdminPassword = "Admin";

            this.LoggerPath = @"conf\logs\";
            this.ConfiguratorPath = @"conf\config.xml";
            this.ResourceFolder = @"conf";
            // cache size, default - 10MB
            this.MaxCacheSize = 10 * 1024 * 1024;
            this.IsCacheEnabled = true;

            // create localhost address by default
            this.Host = IPAddress.Parse("127.0.0.1");
        }

        public string ResourceFolder { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Configurator"/> class. 
        /// :this() executes base constructor and then current one
        /// </summary>
        /// <param name="port">
        /// Port of WebServer to listen to.
        /// </param>
        private Configurator(int port)
            : this()
        {
            this.Port = port;
        }

        #endregion

        #region Public Events

        /// <summary>
        /// The property changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the instance.
        /// </summary>
        [XmlIgnore]
        public static Configurator Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Configurator();
                }

                return instance;
            }

            set
            {
                instance = value;
            }
        }

        /// <summary>
        /// Gets or sets login constant for admin loging
        /// </summary>
        public string AdminLogin { get; set; }

        /// <summary>
        /// Gets or sets password constant for admin logging
        /// </summary>
        public string AdminPassword { get; set; }

        /// <summary>
        ///  Gets or sets path to the Configurator XML file
        /// </summary>
        public string ConfiguratorPath { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether logging functionality is on.
        /// </summary>
        public bool EnableLogging { get; set; }

        /// <summary>
        /// Gets or sets the Host of WebServer
        /// </summary>
        [XmlIgnore]
        public IPAddress Host { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the caching of text or images is enabled.
        /// </summary>
        public bool IsCacheEnabled { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether to encode session
        /// </summary>
        public bool IsCookielessSession { get; set; }

        /// <summary>
        ///   Gets or sets array of other servers for load balancer mode
        /// </summary>
        [XmlArray]
        [XmlArrayItem("Address")]
        public ObservableCollection<string> LoadBalancerAddresses
        {
            get
            {
                return this.loadBalancerAddresses;
            }

            set
            {
                this.loadBalancerAddresses = value;
                this.OnPropertyChanged("LoadBalancerAddresses");
            }
        }

        /// <summary>
        /// Gets or sets port number for load balancer to get data about servers' loads
        /// </summary>
        public int LoadBalancerPort { get; set; }

        /// <summary>
        /// Gets or sets relative or absolute path to the logger folder
        /// </summary>
        public string LoggerPath { get; set; }

        /// <summary>
        /// Gets or sets maximum cache size in bytes
        /// </summary>
        public int MaxCacheSize { get; set; }

        /// <summary>
        /// Gets or sets the max number of users.
        /// </summary>
        public int MaxUsers { get; set; }

        /// <summary>
        /// Gets or sets the port number.
        /// </summary>
        public int Port
        {
            get
            {
                return this.port;
            }

            set
            {
                this.port = value;
                this.OnPropertyChanged("Port");
            }
        }

        /// <summary>
        /// Gets or sets the relative www path.
        /// </summary>
        public string RelativeWwwPath { get; set; }

        /// <summary>
        /// Gets the remote servers list.
        /// </summary>
        public List<string> RemoteServers
        {
            get
            {
                if (this.remoteServers == null)
                {
                    this.remoteServers = new List<string>();
                }

                return this.remoteServers;
            }
        }

        /// <summary>
        /// Gets or sets the server mode.
        /// </summary>
        public ServerConfiguration ServerMode { get; set; }

        /// <summary>
        /// Gets or sets the server name.
        /// </summary>
        public string ServerName { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether to use compression.
        /// </summary>
        public bool UseResponseCompression { get; set; }

        /// <summary>
        /// Gets or sets the server version.
        /// </summary>
        public string Version { get; set; }

        #endregion

        #region Methods

        /// <summary>
        /// The on property changed.
        /// </summary>
        /// <param name="propertyName">
        /// The property name.
        /// </param>
        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}